package com.obas.monitor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.mina.core.session.IoSession;


import com.ease.common.util.Detect;
import com.obas.business.common.vo.AtMessage;
import com.obas.business.common.vo.RunnableStep;
import com.obas.business.common.vo.TestContext;
import com.obas.monitor.manager.FeedManager;


public class MessagePlayer extends Thread {
   private TestContext context;
   private FeedManager feedManager;

   private List<RunnableStep> stepList;

   public MessagePlayer(TestContext context, FeedManager feedManager) {
       this.context = context;
       this.feedManager = feedManager;
   }

   public void run() {
      try {
         readText();
         runSteps();
      } catch (Exception e) {
         e.printStackTrace();
      }
   }

   @SuppressWarnings("unchecked")
   private void runSteps() throws InterruptedException {
      synchronized (context) {
         boolean flag = true;
         for (int ii = 0; ii < stepList.size();) {
             RunnableStep step = context.runningStep =  stepList.get(ii);
             AtMessage msg = step.msg;

             Map<String, Object> param = (Map<String, Object>)msg.getParam();

             if (RunnableStep.FLEX_MSG.equals(step.type) || RunnableStep.VERIFY_FLEX.equals(step.type)) {
                 IoSession session = context.getAppSession(step.appId);
                 while (session == null) {
                    context.wait();
                    session = context.getAppSession(step.appId);
                 }
                 if (RunnableStep.FLEX_MSG.equals(step.type)) {
                     session.write(new AtMessage(msg.getId(), AtCommand.ExecMethod, param));
                 }
                 else {
                     session.write(new AtMessage(msg.getId(), AtCommand.GetProperty, param));
                 }
             }
             else if (RunnableStep.HTML_MSG.equals(step.type)) {
                 context.session.write(new AtMessage(msg.getId(), AtCommand.ExecMethod, param));
             }
             else if (RunnableStep.VERIFY_HTML.equals(step.type)) {
                 context.session.write(new AtMessage(msg.getId(), AtCommand.GetProperty, param));
             }
             feedManager.sendMsg(new AtMessage(msg.getId(), AtCommand.ideSteppingOver, param), context.pageId);

             context.wait();

             if (context.playError) {
                flag = false;
                break;
             }

             if (context.playSuccess) {
                ii++;
             }
         }
         if (flag) {
            feedManager.sendMsg(new AtMessage(genMsgId(), AtCommand.StopRun, null), context.pageId);
         }
         context.player = null;
         context.ideState = AtCommand.ideInited;
         context.notifyAll();
      }
   }

   public void readText() {
      stepList = new ArrayList<RunnableStep>();
      String[] lines = context.script.split("\r");
      for (int i = 0; i < lines.length; i++) {
         String line = lines[i];
         if (line != null) {
            parseStep(line);
         }
      }
   }

   @SuppressWarnings("unchecked")
   public void parseStep(String step) {
      step = StringUtils.trim(step);
      if (StringUtils.isBlank(step)) {
         return;
      }
      RunnableStep rstep = new RunnableStep();
      if (step.startsWith("verify")) {
          Map<String, Object> param = new HashMap<String, Object>();
          int index = step.indexOf("(");
          String propStr = step.substring(index + 1, step.indexOf(", "));
          index = propStr.lastIndexOf(".");
          String partStr = propStr.substring(0, index);

          Object[] parts = getLocatorParts(partStr);
          param.put("parts", parts);
          if (parts.length > 0) {
             Map<String, String> pMap = (Map<String, String>) parts[0];
             if (pMap.get("automationClassName").equals("FlexApplication")) {
                rstep.appId = pMap.get("automationName");
                rstep.type = RunnableStep.VERIFY_FLEX;
             }
             else {
                rstep.type = RunnableStep.VERIFY_HTML;
             }
          }

          String propName = propStr.substring(index + 1);
          String propValue = step.substring(step.indexOf(", ") + 2, step.length() - 1);

          param.put("property", propName);
          param.put("value", propValue);
          param.put("script", step);
          AtMessage msg = new AtMessage(genMsgId(), AtCommand.Verification, param);
          rstep.msg = msg;
      }
      else {
//          String[] strs = step.split(", ");
          int index = step.lastIndexOf(", ");
          Map<String, Object> param = new HashMap<String, Object>();
          String partStr = step.substring(0, index);
          Object[] parts = getLocatorParts(partStr);
          param.put("parts", parts);

          if (parts.length > 0) {
              Map<String, String> pMap = (Map<String, String>) parts[0];
              if (pMap.get("automationClassName").equals("FlexApplication")) {
                 rstep.appId = pMap.get("automationName");
                 rstep.type = RunnableStep.FLEX_MSG;
              }
              else {
                 rstep.type = RunnableStep.HTML_MSG;
              }
           }

          String methodStr = step.substring(index + 2);
          int methodIndex = methodStr.indexOf("(");
          String method = methodStr.substring(0, methodIndex);
          param.put("method", method);
          if (method.equals("waitfor")) {
             rstep.type = RunnableStep.WAIT;
          }
          if (methodIndex < methodStr.length() - 1) {
             String argStr = methodStr.substring(methodIndex + 1, methodStr.length() - 1);
             String[] args = argStr.split(",");
             param.put("args", args);
          }
          else {
             param.put("args", new Object[0]);
          }
          param.put("script", step);
          AtMessage msg = new AtMessage(genMsgId(), AtCommand.ExecMethod, param);
          rstep.msg = msg;
      }
      stepList.add(rstep);
   }

   private Object[] getLocatorParts(String partStr) {
       if (Detect.notEmpty(partStr)) {
           String[] partStrs = partStr.split("->");
           Object[] parts = new Object[partStrs.length];
           for (int i = 0; i < partStrs.length; i++) {
              Map<String, String> pMap = new HashMap<String, String>();
              String partSub = partStrs[i];
              int ii = partSub.indexOf("(");
              pMap.put("automationClassName", partSub.substring(0, ii));
              int jj = partSub.indexOf(", ");
              if (jj != -1) {
                 pMap.put("automationName", partSub.substring(ii + 1, jj));
                 pMap.put("automationIndex", partSub.substring(jj + 2, partSub.length() - 1));
              }
              else {
                 pMap.put("automationName", partSub.substring(ii + 1, partSub.length() - 1));
              }
              parts[i] = pMap;
           }
           return parts;
        }
        else {
           return new Object[0];
        }
   }

   private int curMsgId = 2;
   private int genMsgId() {
       if (curMsgId < Integer.MAX_VALUE - 2) {
           curMsgId = curMsgId + 2;
       }
       else {
           curMsgId = 2;
       }
       return curMsgId;
   }
}
